"""
增强版Kubernetes资源转换器
"""
from typing import Dict, List, Any, Optional, Union
import yaml
import json
import base64
from dataclasses import dataclass
from kubernetes import client
from kubernetes.client.rest import ApiException

@dataclass
class ConversionResult:
    """转换结果"""
    success: bool
    data: Any
    errors: List[str]
    warnings: List[str]

class EnhancedResourceConverter:
    """增强版资源转换器"""
    
    def __init__(self):
        self._k8s_api = client.ApiClient()
        self._version_cache = {}
        
    def convert_resource(self, resource: Dict[str, Any], target_format: str, 
                        target_version: Optional[str] = None) -> ConversionResult:
        """
        转换资源格式和版本
        
        Args:
            resource: 要转换的资源
            target_format: 目标格式 (yaml/json/dict)
            target_version: 目标API版本
            
        Returns:
            ConversionResult: 转换结果
        """
        errors = []
        warnings = []
        
        try:
            # 1. 版本转换
            if target_version:
                converted = self._convert_version(resource, target_version)
                if not converted.success:
                    errors.extend(converted.errors)
                    warnings.extend(converted.warnings)
                    return ConversionResult(False, None, errors, warnings)
                resource = converted.data
            
            # 2. 格式转换
            if target_format == "yaml":
                data = yaml.dump(resource, default_flow_style=False)
            elif target_format == "json":
                data = json.dumps(resource, indent=2)
            elif target_format == "dict":
                data = resource
            else:
                errors.append(f"不支持的格式: {target_format}")
                return ConversionResult(False, None, errors, warnings)
            
            return ConversionResult(True, data, errors, warnings)
            
        except Exception as e:
            errors.append(f"转换失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def convert_template(self, template: Dict[str, Any], variables: Dict[str, Any]) -> ConversionResult:
        """
        转换资源模板
        
        Args:
            template: 资源模板
            variables: 模板变量
            
        Returns:
            ConversionResult: 转换结果
        """
        errors = []
        warnings = []
        
        try:
            # 1. 替换变量
            result = self._replace_variables(template, variables)
            if not result.success:
                errors.extend(result.errors)
                return ConversionResult(False, None, errors, warnings)
            
            # 2. 处理条件
            result = self._process_conditions(result.data)
            if not result.success:
                errors.extend(result.errors)
                return ConversionResult(False, None, errors, warnings)
            
            # 3. 处理循环
            result = self._process_loops(result.data)
            if not result.success:
                errors.extend(result.errors)
                return ConversionResult(False, None, errors, warnings)
            
            return ConversionResult(True, result.data, errors, warnings)
            
        except Exception as e:
            errors.append(f"模板转换失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def convert_references(self, resource: Dict[str, Any], 
                          reference_map: Dict[str, Any]) -> ConversionResult:
        """
        转换资源引用
        
        Args:
            resource: 要转换的资源
            reference_map: 引用映射
            
        Returns:
            ConversionResult: 转换结果
        """
        errors = []
        warnings = []
        
        try:
            # 1. 转换ConfigMap引用
            result = self._convert_configmap_refs(resource, reference_map)
            if not result.success:
                errors.extend(result.errors)
                return ConversionResult(False, None, errors, warnings)
            
            # 2. 转换Secret引用
            result = self._convert_secret_refs(result.data, reference_map)
            if not result.success:
                errors.extend(result.errors)
                return ConversionResult(False, None, errors, warnings)
            
            # 3. 转换其他引用
            result = self._convert_other_refs(result.data, reference_map)
            if not result.success:
                errors.extend(result.errors)
                return ConversionResult(False, None, errors, warnings)
            
            return ConversionResult(True, result.data, errors, warnings)
            
        except Exception as e:
            errors.append(f"引用转换失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def _convert_version(self, resource: Dict[str, Any], target_version: str) -> ConversionResult:
        """转换资源版本"""
        errors = []
        warnings = []
        
        try:
            # 获取当前版本
            current_version = resource.get("apiVersion")
            if not current_version:
                errors.append("资源缺少apiVersion字段")
                return ConversionResult(False, None, errors, warnings)
            
            # 检查版本兼容性
            if not self._is_version_compatible(current_version, target_version):
                errors.append(f"版本 {current_version} 与 {target_version} 不兼容")
                return ConversionResult(False, None, errors, warnings)
            
            # 执行版本转换
            converted = self._perform_version_conversion(resource, current_version, target_version)
            if not converted:
                errors.append("版本转换失败")
                return ConversionResult(False, None, errors, warnings)
            
            return ConversionResult(True, converted, errors, warnings)
            
        except Exception as e:
            errors.append(f"版本转换失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def _replace_variables(self, template: Dict[str, Any], variables: Dict[str, Any]) -> ConversionResult:
        """替换模板变量"""
        errors = []
        warnings = []
        
        try:
            # 将模板转换为字符串
            template_str = yaml.dump(template)
            
            # 替换变量
            for key, value in variables.items():
                placeholder = f"${{{key}}}"
                if isinstance(value, (dict, list)):
                    value = yaml.dump(value)
                template_str = template_str.replace(placeholder, str(value))
            
            # 解析回字典
            result = yaml.safe_load(template_str)
            return ConversionResult(True, result, errors, warnings)
            
        except Exception as e:
            errors.append(f"变量替换失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def _process_conditions(self, resource: Dict[str, Any]) -> ConversionResult:
        """处理条件语句"""
        errors = []
        warnings = []
        
        try:
            # 处理if条件
            if "if" in resource:
                condition = resource["if"]
                if not self._evaluate_condition(condition):
                    return ConversionResult(True, None, errors, warnings)
                del resource["if"]
            
            # 处理when条件
            if "when" in resource:
                condition = resource["when"]
                if not self._evaluate_condition(condition):
                    return ConversionResult(True, None, errors, warnings)
                del resource["when"]
            
            return ConversionResult(True, resource, errors, warnings)
            
        except Exception as e:
            errors.append(f"条件处理失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def _process_loops(self, resource: Dict[str, Any]) -> ConversionResult:
        """处理循环语句"""
        errors = []
        warnings = []
        
        try:
            # 处理for循环
            if "for" in resource:
                loop = resource["for"]
                items = loop.get("items", [])
                template = loop.get("template", {})
                
                results = []
                for item in items:
                    # 替换循环变量
                    item_template = yaml.dump(template)
                    for key, value in item.items():
                        placeholder = f"${{{key}}}"
                        item_template = item_template.replace(placeholder, str(value))
                    
                    # 解析结果
                    result = yaml.safe_load(item_template)
                    results.append(result)
                
                return ConversionResult(True, results, errors, warnings)
            
            return ConversionResult(True, resource, errors, warnings)
            
        except Exception as e:
            errors.append(f"循环处理失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def _convert_configmap_refs(self, resource: Dict[str, Any], 
                              reference_map: Dict[str, Any]) -> ConversionResult:
        """转换ConfigMap引用"""
        errors = []
        warnings = []
        
        try:
            # 处理环境变量引用
            if "spec" in resource and "template" in resource["spec"]:
                containers = resource["spec"]["template"]["spec"].get("containers", [])
                for container in containers:
                    if "env" in container:
                        for env in container["env"]:
                            if "valueFrom" in env and "configMapKeyRef" in env["valueFrom"]:
                                ref = env["valueFrom"]["configMapKeyRef"]
                                if ref["name"] in reference_map:
                                    env["value"] = reference_map[ref["name"]].get(ref["key"])
            
            # 处理卷挂载引用
            if "spec" in resource and "template" in resource["spec"]:
                volumes = resource["spec"]["template"]["spec"].get("volumes", [])
                for volume in volumes:
                    if "configMap" in volume:
                        config_map = volume["configMap"]
                        if config_map["name"] in reference_map:
                            config_map["items"] = reference_map[config_map["name"]]
            
            return ConversionResult(True, resource, errors, warnings)
            
        except Exception as e:
            errors.append(f"ConfigMap引用转换失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def _convert_secret_refs(self, resource: Dict[str, Any], 
                           reference_map: Dict[str, Any]) -> ConversionResult:
        """转换Secret引用"""
        errors = []
        warnings = []
        
        try:
            # 处理环境变量引用
            if "spec" in resource and "template" in resource["spec"]:
                containers = resource["spec"]["template"]["spec"].get("containers", [])
                for container in containers:
                    if "env" in container:
                        for env in container["env"]:
                            if "valueFrom" in env and "secretKeyRef" in env["valueFrom"]:
                                ref = env["valueFrom"]["secretKeyRef"]
                                if ref["name"] in reference_map:
                                    env["value"] = reference_map[ref["name"]].get(ref["key"])
            
            # 处理卷挂载引用
            if "spec" in resource and "template" in resource["spec"]:
                volumes = resource["spec"]["template"]["spec"].get("volumes", [])
                for volume in volumes:
                    if "secret" in volume:
                        secret = volume["secret"]
                        if secret["secretName"] in reference_map:
                            secret["items"] = reference_map[secret["secretName"]]
            
            return ConversionResult(True, resource, errors, warnings)
            
        except Exception as e:
            errors.append(f"Secret引用转换失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def _convert_other_refs(self, resource: Dict[str, Any], 
                          reference_map: Dict[str, Any]) -> ConversionResult:
        """转换其他引用"""
        errors = []
        warnings = []
        
        try:
            # 处理服务引用
            if "spec" in resource:
                if "serviceName" in resource["spec"]:
                    service_name = resource["spec"]["serviceName"]
                    if service_name in reference_map:
                        resource["spec"]["serviceName"] = reference_map[service_name]
                
                if "service" in resource["spec"]:
                    service = resource["spec"]["service"]
                    if service["name"] in reference_map:
                        service["name"] = reference_map[service["name"]]
            
            return ConversionResult(True, resource, errors, warnings)
            
        except Exception as e:
            errors.append(f"其他引用转换失败: {str(e)}")
            return ConversionResult(False, None, errors, warnings)
    
    def _is_version_compatible(self, current_version: str, target_version: str) -> bool:
        """检查版本兼容性"""
        try:
            # 解析版本
            current_parts = current_version.split("/")
            target_parts = target_version.split("/")
            
            if len(current_parts) != 2 or len(target_parts) != 2:
                return False
            
            current_group, current_version = current_parts
            target_group, target_version = target_parts
            
            # 检查API组
            if current_group != target_group:
                return False
            
            # 检查版本号
            current_major = int(current_version.split(".")[0])
            target_major = int(target_version.split(".")[0])
            
            return current_major == target_major
            
        except Exception:
            return False
    
    def _perform_version_conversion(self, resource: Dict[str, Any], 
                                  current_version: str, target_version: str) -> Optional[Dict[str, Any]]:
        """执行版本转换"""
        try:
            # 获取API资源
            api_resources = self._k8s_api.resources.get_api_resources(current_version)
            target_resources = self._k8s_api.resources.get_api_resources(target_version)
            
            # 查找资源类型
            resource_type = None
            for api_resource in api_resources:
                if api_resource.kind == resource["kind"]:
                    resource_type = api_resource
                    break
            
            if not resource_type:
                return None
            
            # 查找目标资源类型
            target_type = None
            for api_resource in target_resources:
                if api_resource.kind == resource["kind"]:
                    target_type = api_resource
                    break
            
            if not target_type:
                return None
            
            # 执行转换
            converted = resource.copy()
            converted["apiVersion"] = target_version
            
            return converted
            
        except Exception:
            return None
    
    def _evaluate_condition(self, condition: Dict[str, Any]) -> bool:
        """评估条件表达式"""
        try:
            # 获取操作符
            operator = next(iter(condition))
            value = condition[operator]
            
            # 评估条件
            if operator == "eq":
                return value[0] == value[1]
            elif operator == "ne":
                return value[0] != value[1]
            elif operator == "gt":
                return value[0] > value[1]
            elif operator == "lt":
                return value[0] < value[1]
            elif operator == "ge":
                return value[0] >= value[1]
            elif operator == "le":
                return value[0] <= value[1]
            elif operator == "in":
                return value[0] in value[1]
            elif operator == "notin":
                return value[0] not in value[1]
            elif operator == "exists":
                return value is not None
            elif operator == "notexists":
                return value is None
            else:
                return False
                
        except Exception:
            return False 